/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/


// 定义三个状态
const PENDING = "PENDING";
const RESOLVED = "RESOLVED";
const REJECTED = 'REJECTED';
function resolvePromise(x, promise2, resolve, reject) {
  //判断x === promise, 抛出类型错误
  if (x === promise2) {
    console.log('======')
    return reject(new TypeError('类型错误'))
  }
  // 允许状态改变一次
  let called = false;



  try {
    //判断x是否包含then属性，thenable
    if (typeof x === 'object' && x !== null) {
      const then = x.then;
      if (typeof then === "function") {
        // console.log(typeof then)
        then.call(x, v => {
          if (called) return;
          called = true;
          resolvePromise(v, promise2, resolve, reject)
        }, r => {
          if (called) return;
          called = true;
          reject(r)
        })
      } else {
        if (called) return;
        called = true;
        resolve(x)
      }
    } else {
      if (called) return;
      called = true;
      resolve(x)
    }
  } catch (e) {
    if (called) return;
    called = true;
    reject(e)
  }
}
class Promise {
  constructor(exectuor) {
    try {
      //捕获执行器错误
      exectuor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }

  status = PENDING;
  value = null;
  reason = null;
  //存储失败和成功的回调
  onFullFilledCallbacks = [];
  onRejectedCallbacks = [];

  static all (args) {
    return new Promise((resolve, reject) => {
      args.reduce((prev, curr, i, arr) => {
        if (curr instanceof Promise) {
          curr.then((v) => {
            prev[i] = v;
            if (prev.length === arr.length) {
              resolve(prev)
            }
          }, r=> {
            reject(r)
          })
        } else {
          prev[i] = curr;
        }
        return prev;
      }, [])
    })
  }
  static resolve (v) {
    if (v instanceof  Promise) return v;
    return new Promise((resolve ,reject) => resolve(v));
  }
  static reject(r) {
    return new Promise((resolve,reject)=>{
      reject(r)
    })
  }
  static allSettled (args) {
    return new Promise((resolve, reject) => {
      function addData(prev, index, value){
        prev[index] = value;
        if (prev.length === args.length) {
          resolve(prev)
        }
      }
      args.reduce((prev, curr, index, arr) => {
        if (curr instanceof Promise) {
          curr.then(res => {
            addData(prev, index, {
              value: res,
              status: 'fulfilled'
            })
          }, r => {
            addData(prev, index, {
              reason: r,
              status: 'rejected'
            })
          })
        } else {
          addData(prev, index, {
            reason: curr,
            status: 'fulfilled'
          })
        }
      })
    })
  }

  static race(args) {
    return new Promise((resolve, reject) => {
      args.forEach((item) => {
        if (item instanceof Promise) {
          item.then(v => {
            resolve(v)
          }, r => {
            reject(r)
          })
        } else {
          resolve(item)
        }
      })
    })
  }

  finally (cb) {
    return this.then(v => {
      return Promise.resolve(cb()).then(() => v);
    }, r => {
      return Promise.resolve(cb()).then(() => { throw r })
    })
  }

  resolve = (v) => {

    //只有状态为pending才执行
    if (this.status === PENDING) {
      this.status = RESOLVED;
      this.value = v;
      this.onFullFilledCallbacks.forEach(c => c())
    }
  }

  reject = (r) => {
    if (this.status === PENDING) {
      this.status = REJECTED;
      this.reason = r;
      this.onRejectedCallbacks.forEach(c => c())
    }
  }

  then(onFullFilled, onRejected) {
    //onFullFilled onRejected类型判断
    if (typeof onFullFilled !== 'function') onFullFilled = v => v;
    if (typeof onFullFilled !== 'function') {
      onRejected = r => {
        throw r;
      }
    }
    const promise2 = new Promise((resolve, reject) => {
      if (this.status === RESOLVED) {
        // Promise为微任务，所以放到微任务队列执行
        queueMicrotask(() => {
          try {
            const x = onFullFilled(this.value);
            resolvePromise(x, promise2, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }

      if (this.status === REJECTED) {
        queueMicrotask(() => {
          try {
            const x = onRejected(this.reason)
            resolvePromise(x, promise2, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }

      if (this.status === PENDING) {
        //如果状态为pending，则执行方法放入数组中，等待resolve或reject时候执行
        this.onFullFilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onFullFilled(this.value);
              resolvePromise(x, promise2, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })

        this.onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              const x = onRejected(this.reason);
              resolvePromise(x, promise2, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2;
  }
}

Promise.deferred = function() {
  var result = {};
  result.promise = new Promise(function(resolve, reject){
    result.resolve = resolve;
    result.reject = reject;
  });

  return result;
}

module.exports = Promise;
